
require 'middletier_interface'
# Require rubyinterface version 1.0 for the middle tier
#eval %q{`wget https://localhost:8443/rubyinterface/1.0`}

#Shoes::Native.class_eval do  
#  def lose_focus
    #window {close}
#  end
#end

class Check2 < Widget
  
  def initialize(opts = {})   
    self.height = 16
    self.margin = opts[:margin] || 2
    self.margin_right = opts[:margin_right] || 4
    self.width = 16 + self.margin_right
    
    @checked = false
    
    stack :width => 16 do
      img = image 'images/check.png', :width => 16, :height => 16
      click do
        @checked = (not @checked)
        img.path = "images/check#{'_checked' if checked?}.png"
      end
    end
    yield if block_given?
  end
  
  def checked?
    @checked
  end
end

class Visual_loader < Widget
  def initialize(opts = {})
    self.width = 32
    self.height = 32
    self.margin = opts[:margin] || 4
    
    stack :width => 32 do
      @img = image 'images/loader/loader0.gif'
    end
    
    i = 0
    @load_ani = app.animate(12) do
      i += 1
      @img.path = "images/loader/loader#{i % 12}.gif"
    end
  end
  
  def start
    @load_ani.start
  end

  def stop
    @load_ani.stop
  end
  
  def remove
    stop
    super
  end
end

class Toolbarbutton < Widget
  def initialize(opts = {}, &blk)
    self.width = 24+4
    self.height = 24
    self.margin = opts[:margin] || 4
    
    @klick = blk
 
    stack :width => 24 do # If :height is set images will flicker on visit / reload
      @img = image opts[:image], :width => 24, :height => 24
      app.click do
        if enabled?
          #set_image_state 'click'
          @klick.call unless @klick.nil?
        end
      end
      release {set_image_state 'hover' if enabled?} # Only fires if the mouse is over the button, hence hover
      hover {set_image_state 'hover' if enabled?}
      leave {set_image_state if enabled?}
    end
    
    @imgpaths = opts[:image].match(/(.*)\.(...)$/)
    self.enabled = opts[:enabled].nil? ? true : opts[:enabled]
  end
    
  def set_image_state(*state)
    @img.path = "#{@imgpaths[1]}#{"_#{state}" unless state.first.nil?}.#{@imgpaths[2]}"
  end
    
  def enabled=(value)
    @enabled = value
    set_image_state enabled? ? nil : 'disabled'
  end
    
  def enabled?
    @enabled
  end
  
  def click(&blk)
    @klick = blk
  end
end

class Toolbarseparator < Widget
  def initialize(opts = {}, &blk)
    self.width = 8+4
    self.height = 24
    self.margin = opts[:margin] || 4

    stack :width => 8 do
      @img = image 'images/separator3.png', :width => 8, :height => 24
    end
  end
end

class Fileshaaarer < Shoes

  url '/', :welcome
  url '/home', :home
  url '/register', :register
  url '/files/(.*)', :search_files
  
  @@back_history = Array.new
  @@forw_history = Array.new

  @@mid = MiddletierInterface.new 'https://localhost:8443'
    
  def welcome
    background rgb(232, 232, 232)
    	
    stack :margin => 10, :margin_bottom => 0, :margin_top => 43 do
      image 'images/logo.png', :margin_bottom => 32
      
      unless @@mid.auth?
        para strong('Welcome to Fileshaaarer, please log in'), :margin => 0, :margin_bottom => 16
        
        para 'Username:', :margin => 0
        uname = edit_line
        
        para 'Password:', :secret => true, :margin => 0, :margin_top => 8
        pwd = edit_line
        
        button 'Log in', :margin_top => 8, :click => proc {
          @@mid.user = uname.text
          @@mid.password = pwd.text
          case @@mid.auth?
            when true : #visit_with_history '/home'
              app.visit '/home'
            when false : 
              alert 'wrong username and/or password'
              uname.focus
          end
        }
        
        para 'Not registered? ', link('Register Now!', :click => proc {visit_with_history '/register'}), :margin_top => 32
        
        para 'Want to know what you are missing?', :margin_bottom => 0, :margin_top => 32
        para 'Take a ', link('Sneak Peek', :click => proc {
          @@mid.user = 'guest'
          @@mid.password = 'guest'
          visit_with_history '/home'
        })
      
      else
      
        app.visit '/home'
      
      end
      
    end
    
    toolbar
    @search_box.state = 'disabled'
    @upload_button.enabled = false
  end
  
  def home
    background rgb(232, 232, 232)
    
    stack :margin => 10, :margin_bottom => 0, :margin_top => 43 do
      image 'images/logo.png', :margin_bottom => 32
      para strong("Welcome #{@@mid.user}, begin shaaaring!"), :margin => 0, :margin_bottom => 16
      
      button 'Log out'  do
        @@mid.user = ''
        @@mid.password = ''
        @@back_history.clear
        @@forw_history.clear
        app.visit '/'
      end if @@mid.auth?
    end
    
    toolbar
  end
  
  def register
    background rgb(232, 232, 232)
    
    stack :margin => 10, :margin_bottom => 0, :margin_top => 43 do
      image 'images/logo.png', :margin_bottom => 32
      
      para strong('Register a new user'), :margin => 0, :margin_bottom => 16
      
      para 'Username:', :margin => 0
      flow do
        @username = edit_line do |e|
          # FIXME: Check available usernames
          #if e.text.length > 0
          #  @username_stat.text = 'ok'
          #  @username_stat.style :stroke => green
          #else
          #  @username_stat.text = ' '
          #end
        end
        
        #@username_stat = para ' ' #, :stroke => green
      end
      
      para 'Password:', :secret => true, :margin => 0
      @passwd = edit_line do |e|
        if @confpasswd.text == e.text and e.text.length > 0
          @password_stat.text = 'ok'
          @password_stat.style :stroke => green
          @regbutton.state = nil
        elsif e.text.length > 0
          @password_stat.text = 'missmatch'
          @password_stat.style :stroke => red
          @regbutton.state = 'disabled'
        else
          @password_stat.text = ' '
          @regbutton.state = 'disabled'
        end
      end
      
      para 'Confirm Password:', :secret => true, :margin => 0, :margin_top => 8
      flow do
        @confpasswd = edit_line do |e|
          if @passwd.text == e.text and e.text.length > 0
            @password_stat.text = 'ok'
            @password_stat.style :stroke => green
            @regbutton.state = nil
          elsif e.text.length > 0
            @password_stat.text = 'missmatch'
            @password_stat.style :stroke => red
            @regbutton.state = 'disabled'
          else
            @password_stat.text = ' '
            @regbutton.state = 'disabled'
          end
        end
        @password_stat = para ' ' #, :stroke => red
      end
      
      @regbutton = button 'Register', :margin_top => 8, :state => 'disabled', :click => proc {
        case (resp = @@mid.register_user @username.text, @passwd.text)[:status]
          when 201: 
			alert 'user registered'
			@@mid.user = @username.text
            @@mid.password = @passwd.text
			app.visit '/home'
          else 
            alert 'name already taken'
            @username.focus
        end
      }
      
    end
    
    toolbar
    @search_button.enabled = false
    @search_box.state = 'disabled'
  end
  
  def search_files(query)
    query = URI.unescape query
    
    background rgb(232, 232, 232)
    
    stack :margin => 10, :margin_bottom => 0, :margin_top => 43, :margin_bottom => 8, :width => '100%' do
      image 'images/logo.png', :margin_bottom => 32
    
      para strong("Search result"), :margin => 0
          
      col_width = "#{100 / 2.1}%"
          
      if query =~ /owner:/
        match = query.match(/(.*)owner:([^\s]*)(.*)/)
        user_query = match[2]
        file_query = match[1] + match[3]
      else
        user_query = '.'
        file_query = query
      end
      
      user_query.strip!
      file_query.strip!
      
      file_query = '.' if file_query == ''
      user_query = '.' if user_query == ''
      
      # FIXME: Show loader 
      vis_load = visual_loader
      @t = Thread.new do
        Thread.stop        
        result = @@mid.query_files user_query, file_query
        vis_load.remove
      
        case result[:status] # FIXME: own thread
          when 200 :
            flow :width => '100%', :margin_top => 16, :margin_left => 16 do
              stack :margin => 0, :width => col_width do
                para strong('name'), :margin => 0, :margin_left => 16+16
  
                result[:entry].each do |file|
                  flow do
                    stack :width => 16 do
                      if file[:owner] == @@mid.user or @@mid.role == 'admin'
                        img = image 'images/file_delete.png'
                        hover {img.path = 'images/file_delete_hover.png'}
                        leave {img.path = 'images/file_delete.png'}
                        click do
                          delete file[:id]
                        end
                      else
                        img = image 'images/file_delete_disabled.png'
                      end
                    end
                    
                    para link(file[:name], :click => proc {download file[:id]}), :margin => 0, :margin_left => 16
                  end
                end
              end
              
              stack :margin => 0, :width => col_width do
                 para strong('owner'), :margin => 0
  
                result[:entry].each do |file|
                  para link(file[:owner], :click => proc {visit_with_history "/files/owner:#{file[:owner]}"}), :margin => 0
                end
              end
            end
          else
            alert "Could not query the fileshaaaring server, code: #{result[:status]}"
        end
      end
    end
    
    toolbar
    @search_box.text = query
    @search_button.enabled = query.length > 0
    
    # Spinlock
    until @t.stop?
    end
    @t.run
  end
  
  def search_input(e, search_button)
    search_button.enabled = e.text.length > 0
    
    org_text = e.text;
    e.text = e.text.gsub(/[\n\r\t]/, '') if e.text =~ /[\n\r\t]/
        
    case org_text
      when /.*\n/ : 
        # Search!
        #e.lose_focus
        #search_files(e.text)
        visit_with_history "/files/#{URI.escape e.text}"
      #when /.*\t/ : e.lose_focus
    end
  end
  
  def visit_with_history (path)
    @@back_history << app.location
    visit path
  end

  def toolbar
    flow :height => 33, :attach => Window, :top => 0, :left => 0 do
      background rgb(128, 128, 128)..rgb(200, 200, 200), :height => 32
      background black, :height => 1, :top => 32
  
      toolbarbutton :image => 'images/direction_left.png', :enabled => (not @@back_history.empty?) do
        unless (back = @@back_history.pop).nil?
          @@forw_history << app.location
          visit back
        end
      end

      toolbarbutton :image => 'images/direction_right.png', :enabled => (not @@forw_history.empty?) do
        unless (forw = @@forw_history.pop).nil?
          visit_with_history forw
        end
      end
      
      toolbarbutton :image => 'images/refresh3.png' do
        app.visit app.location
      end
      
      toolbarseparator
      @upload_button = toolbarbutton :image => 'images/upload.png', :enabled => (@@mid.role != 'guest')  do
        upload
      end
      
      @search_button = toolbarbutton :right => 4+16,  :image => 'images/search.png', :enabled => false do
        @search_box.text += "\n"
        search_input @search_box, @search_button
      end
      
      @search_box = edit_box :right => 32+16, :top => 4, :height => 28 do |e|
        search_input e, @search_button
      end
      
      yield if block_given?
    end
  end
  
  def download(fileid)
    unless (file_name = ask_save_file).nil?
      case (resp = @@mid.get_file(@@mid.user, fileid))[:status]
        when 200 : File.open(file_name, 'wb') {|f| f.write(resp[:entry]) }
        when 401: alert 'Please register do download files!'
        else alert 'Could not download file'
      end
    end
  end
  
  def upload
     unless (file_name = ask_open_file).nil?
     
        name = file_name[/([^\/]+)$/, 1]
        file = File.open file_name, 'rb'
        write_resp = @@mid.put_file @@mid.user, URI.escape(name), file.read
        file.close
        
        case write_resp[:status]
          when 201 : visit_with_history URI.escape "/files/owner:#{@@mid.user} #{name}"
          else alert "Could not upload the file #{name}"
        end
      end
  end
  
  def delete(fileid)
    if confirm 'Are you sure?'
      resp = @@mid.delete_file(@@mid.user, fileid)
      alert 'Could not delete the file.' unless resp[:status] == 204
      app.visit app.location
    end
  end
  
  def download_entry (table_name, row_id, col_name, col_mime)    
    background rgb(232, 232, 232)
    s = stack :margin => 10, :margin_top => 42 do      
      vis_load = visual_loader
      @t = Thread.new do
        Thread.stop        
        @resp = @@bin.read_row_entry_for_table table_name, :row => row_id, :column_name => col_name, :column_mime => col_mime
        vis_load.remove        
        case @resp[:status]
        when 200 :
            @dl_button.enabled = true
            @ul_button.enabled = true
            yield(s, @resp[:entry]) if block_given?            
        when 204 :
            s.append {para app.location[/(.*);/, 1], ': ', strong('No Content'), :margin => 0}
            @ul_button.enabled = true
        when 404 : 
            s.append {para app.location[/(.*);/, 1], ': ', strong('Not Found'), :margin => 0}
        end  
      end
    end

    toolbar do
      toolbarseparator
      @dl_button = toolbarbutton :image => 'images/download.png', :enabled => false  do
        unless (file_name = ask_save_file).nil?
          file_name += (".#{col_mime[/\/(.*)/, 1]}" unless file_name =~ /.#{col_mime[/\/(.*)$/, 1]}$/) if col_mime =~ /^image\//
          file = File.new file_name, 'wb'
          file.write @resp[:entry]
          file.close
        end
      end
      @ul_button = toolbarbutton :image => 'images/upload.png', :enabled => false  do
        unless (file_name = ask_open_file).nil?
          file = File.open file_name, 'rb'
          write_resp = @@bin.write_row_entry_for_table table_name, :row => row_id, :column_name => col_name, :entry => file.read
          file.close
          
          case write_resp[:status].to_f
            when 201 : app.visit app.location
            else alert "Could not upload : #{write_resp[:status]}"
          end
        end
      end
    end
    
    # Spinlock
    until @t.stop?
    end
    @t.run
  end
end

Shoes.app :width => 400, :height => 480, :title => 'Fileshaaarer'
